package com.ezhan.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.ezhan.logging.LogManager.log;

/*
 1.系统变量优先级高于用户变量
 2.存在两个java版本，如果用户变量中没有设置，系统变量设置了bin路径，用户默认指向C:\Program Files\Common Files\Oracle\Java\javapath，导致无法正确得到对应版本
 3.目前jdk安装，设置了系统变量，但是在用户变量的path中没有设置，会默认指向C:\Program Files\Common Files\Oracle\Java\javapath
 4.解决方法：① 在用户变量设置jdk的bin路径 ② 删除系统变量中的 C:\Program Files\Common Files\Oracle\Java\javapath  ③ 删除物理链接  ④ 重启Windows资源管理器（explorer.exe）,后续可以优化
 */
public class EnvUtils {
    private static final String ORACLE_JAVAPATH = "C:\\Program Files\\Common Files\\Oracle\\Java\\javapath";

    //判断目标路径是否存在于系统变量
    public static boolean isAlreadyInPath(String target_path) {
        String pathVar = System.getenv("PATH");
        return Arrays.stream(pathVar.split(";"))  //将字符串按照;进行拆分为路径数组，并转化为流
                .map(String::trim)  //对路径使用trim去除首尾空格
                .anyMatch(path -> path.equalsIgnoreCase(target_path));  //忽略大小写匹配
    }

    //加入系统变量
    public boolean addToPathWithSafetyCheck(String target_path) {
        try {
            // 系统path
            String sysPaths = cleanOraclePath();
            log(sysPaths);

            // 构建系统PATH（确保格式正确）
            String sysPath = target_path + ";" + sysPaths;

            // 更新系统PATH（需要管理员）
            if (updateSystemPath(sysPath)) {
                // 更新用户PATH（无需管理员）,只需要在jdk安装时执行
                if (target_path.contains("jdk")) {
                    // 重启Windows资源管理器（explorer.exe），刷新环境变量的缓存和继承关系
                    String explorerPath = System.getenv("SystemRoot") + "\\explorer.exe";
                    ProcessBuilder explorerBuilder = new ProcessBuilder(
                            "taskkill", "/f", "/im", "explorer.exe"
                    );
                    if(explorerBuilder.start().waitFor() != 0){
                        return false;
                    };

                    new ProcessBuilder(explorerPath).start().waitFor();

                    // 用户PATH
                    String userPath = getUserPathFromRegistry();
                    log(userPath);
                    // 构建用户PATH
                    String newUserPath = target_path + ";" + userPath;
                    //  更新用户PATH
                    return updateUserPath(newUserPath);
                }
                return true;
            }

        } catch (Exception e) {
            log("环境变量更新失败: " + e.getMessage());
            return false;
        }
        return false;
    }

    // 更新系统PATH
    private boolean updateSystemPath(String newPath) throws Exception {
        return executeRegCommand(
                "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
                newPath,
                "REG_EXPAND_SZ"
        );
    }

    // 更新用户PATH
    private boolean updateUserPath(String newPath) throws Exception {
        return executeRegCommand(
                "HKEY_CURRENT_USER\\Environment",
                newPath,
                "REG_EXPAND_SZ"
        );
    }

    // 通用注册表更新方法
    private boolean executeRegCommand(String keyPath, String value, String regType) throws Exception {
        // 构建注册表命令
        List<String> command = new ArrayList<>(Arrays.asList(
                "reg", "add", keyPath, "/v", "Path", "/t", regType, "/d", value, "/f"
        ));

        // 执行命令
        ProcessBuilder builder = new ProcessBuilder(command);
        builder.redirectErrorStream(true);
        Process process = builder.start();

        // 读取输出
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), "GBK"))) { // 中文系统编码
            while (reader.readLine() != null) {
                log(reader.readLine());
            }
        }

        return process.waitFor() == 0;
    }

    // 获取系统注册表PATH内容
    public static String getSystemPathFromRegistry() throws Exception {
        return getRegistryValue(
                "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
                "Path"
        );
    }

    // 获取用户注册表PATH内容
    public static String getUserPathFromRegistry() throws Exception {
        return getRegistryValue(
                "HKCU\\Environment",
                "Path"
        );
    }

    //  查询注册表内容
    private static String getRegistryValue(String key, String valueName) throws Exception {
        // 构建reg query命令
        ProcessBuilder builder = new ProcessBuilder(
                "reg", "query", key, "/v", valueName
        );
        builder.redirectErrorStream(true);
        Process process = builder.start();

        // 读取命令输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), "GBK"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                log(line);
                output.append(line).append("\n");
            }
        }

        // 解析输出
        if (process.waitFor() == 0) {
            // 解析类似: "    Path    REG_EXPAND_SZ    C:\Windows\system32"
            /*
            \\s+   1个或多个空格
            \\w+   注册表类型
            \\s+   1个或多个空格
            (.+)   值内容（直至行尾）
             */
            Pattern pattern = Pattern.compile(valueName + "\\s+[\\w-]+\\s+(.+)");
            Matcher matcher = pattern.matcher(output.toString());
            if (matcher.find()) {
                return matcher.group(1);
            }
        }
        return null;
    }

    private static String removeOraclePaths(String path) {
        if (path == null || path.isEmpty()) {
            return path;
        }
        // 按分号分割，然后过滤掉包含"Oracle"的路径
        String[] parts = path.split(";");
        return Arrays.stream(parts)
                .filter(part -> !part.contains(ORACLE_JAVAPATH))
                .collect(Collectors.joining(";"));
    }

    public static String cleanOraclePath() throws Exception {
        //1. 删除物理链接
        deleteSymbolicLink(ORACLE_JAVAPATH);
        // 2. 清理系统PATH
        String systemPath = getRegistryValue(
                "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
                "Path"
        );
        String cleanSystemPath = removeOraclePaths(systemPath);

        return cleanSystemPath;

    }

    //  删除物理符号链接
    private static void deleteSymbolicLink(String path) throws IOException {
        Path linkPath = Paths.get(path);
        if (Files.exists(linkPath)) {
            // 检查是否为符号链接
            if (Files.isSymbolicLink(linkPath)) {
                Files.delete(linkPath);
            }
            // 如果是目录（可能不是链接）
            else if (Files.isDirectory(linkPath)) {
                // 递归删除目录
                Files.walk(linkPath)
                        .sorted(Comparator.reverseOrder())
                        .map(Path::toFile)
                        .forEach(File::delete);
            }
        }
    }
}
